#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <math.h>
#include <glew.h>
#include <glut.h>
#include <Cg/cgGL.h>

#pragma comment( lib,"glew32.lib" )
#pragma comment( lib,"cg.lib" )
#pragma comment( lib,"cgGL.lib" )
#pragma comment( lib,"cv.lib" )
#pragma comment( lib,"highgui.lib" )
#pragma comment( lib,"cxcore.lib" )

int N;
int texSizeX,texSizeY;
GLuint readID,writeID,infoID;
GLuint fb;
GLuint glutWindowHandle;

CGcontext cgContext;
CGprofile fragmentProfile;
CGprogram fragmentProgram;
CGparameter cgData,cgInfo;
int imgw,imgh,imgx,imgy,len;

float* data;
float* result;
float *info;
FILE *f;


void display()
{


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glDrawPixels(imgw,imgh,GL_RGB,GL_FLOAT,result);

	glutSwapBuffers();

}



int main(int argc, char **argv)
{
	int index;



	
	float a,b;
	//char buf[1024];



	imgw=631;
	imgh=437;

	int n=imgw*imgh;



	/*for (int i=0;i<imgh;i++)
	{
		for (int j=0;j<imgw;j++)
		{
			int offset=i*imgw*3+j*3;
			printf("%f %f %f \n",info[offset],info[offset+1],info[offset+2]);
		}
	}*/

	


	IplImage *pImage=cvLoadImage("tifa1.jpg",CV_LOAD_IMAGE_COLOR);
	IplImage *pimg=cvCreateImage(cvSize(imgw,imgh),8,3);
	//cvRectangle(pimg,cvPoint(-1,-1),cvPoint(pimg->width-1,pimg->height-1),CV_RGB(0,0,0),CV_FILLED);

	if (pImage->nChannels!=3||pImage->depth!=IPL_DEPTH_8U||pImage->dataOrder!=0)
	{
		return -1;
	}

	int istep=pImage->widthStep;
	int iheight=pImage->height;
	int iwidth=pImage->width;
	unsigned char *sdata=(unsigned char*)pImage->imageData;



	N = imgw*imgh*3;	
	texSizeX=imgw;
	texSizeY=imgh;
	data = new float[iheight*iwidth*3];
	result = new float[N];

	for (int i=0; i<iheight*iwidth*3; i++) {
		data[i] = sdata[i];
	}

	/************************************************************************/
	/* Start                                                                */
	/************************************************************************/


	/************************************************************************/
	/* Initialize Operation                                                 */
	/************************************************************************/

	glutInit ( &argc, argv );
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize(imgw, imgh);
	glutWindowHandle = glutCreateWindow("GPGPU");
	glutDisplayFunc(display);
	glewInit();

	/************************************************************************/
	/* Create and Bind FBO                                                  */
	/************************************************************************/

	glGenFramebuffersEXT(1, &fb); 
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
	

	/************************************************************************/
	/* Configure Culling Space                                              */
	/************************************************************************/

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, texSizeX, 0.0, texSizeY);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, texSizeX, texSizeY);

	/************************************************************************/
	/* Create and Configure Textures                                        */
	/************************************************************************/

	glGenTextures(1,&readID);
	glGenTextures(1,&writeID);


	glBindTexture(GL_TEXTURE_RECTANGLE_ARB,readID);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGB32F_ARB,iwidth,iheight,0,GL_RGB,GL_FLOAT,0);

	glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,iwidth,iheight,GL_RGB,GL_FLOAT,data);			//Send Data to the Visual Memory





	glBindTexture(GL_TEXTURE_RECTANGLE_ARB,writeID);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGB32F_ARB,texSizeX,texSizeY,0,GL_RGB,GL_FLOAT,0);

	//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	/************************************************************************/
	/* Initialize Nvidia Cg Environment                                     */
	/************************************************************************/

	cgContext = cgCreateContext();
	fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
	cgGLSetOptimalOptions(fragmentProfile);
	fragmentProgram = cgCreateProgramFromFile (cgContext, CG_SOURCE, "GP_F.cg", fragmentProfile, NULL, NULL);
	cgGLLoadProgram (fragmentProgram);
	cgData = cgGetNamedParameter (fragmentProgram, "textureY");
	cgInfo = cgGetNamedParameter(fragmentProgram,"textureInfo");

	/************************************************************************/
	/* Initialize Essential Buffers or Environment                          */
	/************************************************************************/

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, writeID, 0);
	cgGLEnableProfile(fragmentProfile);
	cgGLBindProgram(fragmentProgram);

	glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);

	cgGLSetTextureParameter(cgData, readID);
	cgGLEnableTextureParameter(cgData);

	cgGLSetTextureParameter(cgInfo, infoID);
	cgGLEnableTextureParameter(cgInfo);

	/************************************************************************/
	/* Trigger GPU Computation                                              */
	/************************************************************************/

	glPolygonMode(GL_FRONT,GL_FILL);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(texSizeX, 0.0); 
	glVertex2f(texSizeX, 0.0);
	glTexCoord2f(texSizeX, texSizeY); 
	glVertex2f(texSizeX, texSizeY);
	glTexCoord2f(0.0, texSizeY); 
	glVertex2f(0.0, texSizeY);
	glEnd();

	/************************************************************************/
	/* Read Buffers to Get the Feedback                                     */
	/************************************************************************/

	glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
	glReadPixels(0, 0, texSizeX, texSizeY,GL_RGB,GL_FLOAT,result);

	/************************************************************************/
	/* Release Resource                                                    */
	/************************************************************************/

	cgDestroyProgram(fragmentProgram);
	cgDestroyContext(cgContext);
	glDeleteFramebuffersEXT(1,&fb);
	glDeleteTextures(1,&readID);
	glDeleteTextures(1,&writeID);
	glDeleteTextures(1,&infoID);
	glutDestroyWindow (glutWindowHandle);


	/************************************************************************/
	/* End                                                                  */
	/************************************************************************/

	

	for (int i=0; i<N; i++)
		result[i]=result[i]/255.0;
		//printf("%f\n",result[i]);

	for (int i=0;i<100*3;i+=3)
	{
		printf("%f %f %f \n",result[i],result[i+1],result[i+2]);
	}

	/*for (int i=0;i<imgh;i++)
	{
		for (int j=0;j<imgw;j++)
		{
			int offset=i*imgw*3+j*3;
			printf("%f %f %f \n",result[offset],result[offset+1],result[offset+2]);
		}
	}*/

	glutInit ( &argc, argv );
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize(imgw, imgh);
	glutWindowHandle = glutCreateWindow("GPGPU");
	glutDisplayFunc(display);

	glutMainLoop();

	/*cvNamedWindow("Cal",1);
	cvShowImage("Cal",pimg);
	cvWaitKey(0);
	cvReleaseImage(&pImage);
	cvDestroyWindow("Cal");*/

	delete [] result;
	delete [] data;

	return 0;
}